import asyncio
import base64
from io import BytesIO
from typing import Any

import cv2
import numpy as np
from fastapi import APIRouter, websockets
import adbutils
from starlette.responses import StreamingResponse
from starlette.websockets import WebSocketDisconnect
from .models.request_models import (
    OcrRectRequestV0,
    DeviceClickRequestV0,
    DeviceAppInfoRequestV0,
    DevicSwipeRequestV0,
    DeviceAppOperationRequestV0,
    DeviceTypeTextRequestV0, DeviceTypeTextWithPositionRequestV0)
from ocr.cn_ocr import ocr_image, ocr_image_rect
from .tools import resolution_manager
from pyscrcpy.core import Client
router = APIRouter()

@router.get("/devices",description="获取设备列表")
async def get_devices():
    raw_devices = adbutils.adb.device_list()
    processed_devices = []
    for device in raw_devices:
        device_dict = {}
        for key, value in device.__dict__.items():
            # 去除属性名前的下划线
            new_key = key.lstrip('_')
            if isinstance(value, dict):
                inner_dict = {}
                for inner_key, inner_value in value.items():
                    # 处理嵌套字典，去除属性名前的下划线
                    inner_new_key = inner_key.lstrip('_')
                    inner_dict[inner_new_key] = inner_value
                device_dict[new_key] = inner_dict
            else:
                device_dict[new_key] = value
        processed_devices.append(device_dict)
    return processed_devices


@router.websocket("/screen_stream/{device_id}")
async def screen_stream(websocket: websockets.WebSocket, device_id: str):
    await websocket.accept()
    client = None
    try:
        # 连接到设备
        device = adbutils.adb.device(serial=device_id)
        # 初始化scrcpy客户端，调整参数降低延迟
        client = Client(
            device=device,
            max_fps=15,
            bitrate=2000000,
        )
        loop = asyncio.get_event_loop()
        frame_queue = asyncio.Queue(maxsize=10)  # 最多缓存2帧

        def on_frame(_, frame):
            # 在子线程中处理帧，避免阻塞事件循环
            asyncio.run_coroutine_threadsafe(process_frame(frame, frame_queue), loop)

        client.on_frame(on_frame)
        client.start(True)  # 非阻塞模式启动

        # 持续发送最新帧
        while True:
            jpeg_data = await frame_queue.get()
            await websocket.send_bytes(jpeg_data)

    except WebSocketDisconnect:
        print(f"前端断开连接，设备ID: {device_id}")
    except Exception as e:
        print(f"流传输错误: {e}")
    finally:
        if client:
            client.stop()  # 确保释放资源

@router.websocket("/screen_stream_v2/{device_id}")
async def screen_stream_v2(websocket: websockets.WebSocket, device_id: str):
    await websocket.accept()
    try:
        # 连接到设备
        device = adbutils.adb.device(serial=device_id)
        loop = asyncio.get_event_loop()  # 获取事件循环
        # 初始化scrcpy客户端，调整参数降低延迟
        from functools import partial
        while True:
            # 将同步操作提交到线程池执行（避免阻塞事件循环）
            screen_shot = await loop.run_in_executor(None, device.screenshot)  # 异步获取截图
            # 异步调整图片尺寸（resize是PIL的同步方法）
            screen_resize = await loop.run_in_executor(None, screen_shot.resize, (108*5, 192*5))
            bytes_io = BytesIO()
            # 异步保存图片到字节流（save是PIL的同步方法）
            save_func = partial(screen_resize.save, bytes_io, format="JPEG", quality=65)
            await loop.run_in_executor(None,save_func)
            bytes_io.seek(0)
            await websocket.send_bytes(bytes_io.getvalue())
            await asyncio.sleep(0.1)  # 异步休眠，不阻塞
    except Exception as e:
        print(f"获取设备信息错误: {e}")
        await websocket.close()
        return

async def process_frame(frame, frame_queue):
    # 调整分辨率和质量
    resized_frame = cv2.resize(frame, (800, 600))
    # 在子线程中执行CPU密集型编码
    success, jpeg_bytes = await asyncio.get_event_loop().run_in_executor(
        None,
        lambda: cv2.imencode('.jpg', resized_frame, [int(cv2.IMWRITE_JPEG_QUALITY), 50])
    )
    if success:
        jpeg_data = jpeg_bytes.tobytes()
        # 更新队列，保留最新帧
        if frame_queue.full():
            await frame_queue.get()  # 丢弃旧帧
        await frame_queue.put(jpeg_data)


@router.get("/screen_shot/{device_id}",description="获取屏幕截图",summary="获取屏幕截图")
async def screen_shot(device_id: str="48ef006c"):
    device = adbutils.adb.device(serial=device_id)
    image = device.screenshot()
    resized_image = image.resize((1080, 1920))
    buffered = BytesIO()
    resized_image.save(buffered, format="JPEG", quality=85)
    buffered.seek(0)  # 将文件指针移动到流的起始位置
    return StreamingResponse(
        buffered,
        media_type="image/jpeg",
        headers={"Content-Disposition": "inline; filename=screenshot.png"}
    )

def make_serializable(data: Any) -> Any:
    """
    将数据转换为 JSON 可序列化的对象。

    :param data: 输入的数据
    :return: 可序列化的数据
    """
    if isinstance(data, (int, float, str, bool, type(None))):
        return data
    elif isinstance(data, (list, tuple)):
        return [make_serializable(item) for item in data]
    elif isinstance(data, dict):
        return {key: make_serializable(value) for key, value in data.items()}
    elif isinstance(data,np.ndarray):
        left = int(np.min(data[:, 0]))
        top = int(np.min(data[:, 1]))
        right = int(np.max(data[:, 0]))
        bottom = int(np.max(data[:, 1]))
        return {
            left:left,
            top:top,
            right:right,
            bottom:bottom
        }
    else:
        return str(data)
@router.get("/screen_ocr/{device_id}",description="屏幕识别",summary="屏幕识别")
async def screen_ocr(device_id: str="48ef006c"):
    device = adbutils.adb.device(serial=device_id)
    image = device.screenshot()
    resized_image = image.resize((1080, 1920))
    buffered = BytesIO()
    resized_image.save(buffered, format="JPEG", quality=85)
    buffered.seek(0)  # 将文件指针移动到流的起始位置
    #获取图片
    img_base64 = base64.b64encode(buffered.getvalue()).decode("utf-8")
    img = f"image/jpeg;base64,{img_base64}"
    #ocr识别
    ocr_res = ocr_image(image)
    serializable_ocr_res = make_serializable(ocr_res)
    return {
        "img":img,
        "ocr":serializable_ocr_res,
        "message":"success"
    }

@router.post("/screen_ocr_rect",description="屏幕区域识别",summary="屏幕区域识别")
async def screen_ocr_rect(request_param:OcrRectRequestV0):
    device_id = request_param.device_id
    device = adbutils.adb.device(serial=device_id)
    left = request_param.left
    top = request_param.top
    right = request_param.right
    bottom = request_param.bottom
    image = device.screenshot()
    resized_image = image.resize((1080, 1920))
    buffered = BytesIO()
    resized_image.save(buffered, format="JPEG", quality=85)
    buffered.seek(0)  # 将文件指针移动到流的起始位置
    #获取图片
    img_base64 = base64.b64encode(buffered.getvalue()).decode("utf-8")
    img = f"image/jpeg;base64,{img_base64}"
    #ocr识别
    ocr_res = ocr_image_rect(image,left,top,right,bottom)
    serializable_ocr_res = make_serializable(ocr_res)
    return {
        "img":img,
        "ocr":serializable_ocr_res,
        "message":"success"
    }

@router.post("/click",description="点击屏幕",summary="点击屏幕")
async def click(click_request:DeviceClickRequestV0):
    device_id = click_request.device_id
    x = click_request.x
    y = click_request.y
    device = adbutils.adb.device(serial=device_id)
    real_size= resolution_manager.get_resolution(device)
    # 将点击坐标转换为实际设备坐标
    x = int(x / 1080 * real_size.width)
    y = int(y / 1920 * real_size.height)
    print("real_position",x,y)
    res= device.click(x,y)
    print(res)
    return {
        "message":"success"
    }

@router.post("/swipe",description="滑动屏幕",summary="滑动屏幕")
async def swipe(click_request:DevicSwipeRequestV0):
    device_id = click_request.device_id
    x1 = click_request.start_x
    y1 = click_request.start_y
    x2 = click_request.end_x
    y2 = click_request.end_y
    device = adbutils.adb.device(serial=device_id)
    real_size = resolution_manager.get_resolution(device)
    # 将点击坐标转换为实际设备坐标
    x1 = int(x1 / 1080 * real_size.width)
    y1 = int(y1 / 1920 * real_size.height)
    x2 = int(x2 / 1080 * real_size.width)
    y2 = int(y2 / 1920 * real_size.height)
    device.swipe(x1,y1,x2,y2,1)
    return {
        "message":"success"
    }

@router.post("/type_text",description="输入文字",summary="输入文字")
async def type_text(type_text_request:DeviceTypeTextRequestV0):
    device_id = type_text_request.device_id
    text = type_text_request.text
    device = adbutils.adb.device(serial=device_id)
    device.send_keys(text)
    return {
        "message":"success"
    }

@router.post("/type_text_with_position",description="输入文字",summary="输入文字")
async def type_text_with_position(type_text_request:DeviceTypeTextWithPositionRequestV0):
    device_id = type_text_request.device_id
    text = type_text_request.text
    x = type_text_request.x
    y = type_text_request.y
    device = adbutils.adb.device(serial=device_id)
    real_size = resolution_manager.get_resolution(device)
    # 将点击坐标转换为实际设备坐标
    x = int(x / 1080 * real_size.width)
    y = int(y / 1920 * real_size.height)
    device.click(x,y)
    await  asyncio.sleep(0.5)
    device.send_keys(text,x,y)
    return {
        "message": "success"
    }
@router.get("/device_info/{device_id}",description="获取设备信息",summary="获取设备信息")
async def get_device_info(device_id: str="48ef006c"):
    device = adbutils.adb.device(serial=device_id)
    return device.info

@router.get("/current_app/{device_id}",description="获取当前应用",summary="获取当前应用")
async def get_current_app(device_id: str="48ef006c"):
    device = adbutils.adb.device(serial=device_id)
    return device.app_current()

@router.get("/app_list/{device_id}",description="获取应用列表",summary="获取应用列表")
async def get_app_list(device_id: str="48ef006c"):
    device = adbutils.adb.device(serial=device_id)
    return device.app_list()


@router.post("/app_info",description="获取应用信息",summary="获取应用信息")
async def get_app_info(request_param:DeviceAppInfoRequestV0):
    device = adbutils.adb.device(serial=request_param.device_id)
    app_id = request_param.package_name
    if app_id == "":
        return device.app_current(
            {
                "package": "com.android.settings",
                "activity": "com.android.settings.Settings",
                "flags": 0,
                "options": {
                    "wait": True,
                    "waitForIdle": True,
                    "waitForSelector": True,
                    "waitForSelectorTimeout": 10000
                }
            }
        )

    return device.app_info(app_id)

@router.post("/app_operation",description="应用操作",summary="应用操作")
async def app_operation(request_param:DeviceAppOperationRequestV0):
    device = adbutils.adb.device(serial=request_param.device_id)
    package_name = request_param.package_name
    activity_name = request_param.activity_name
    operation = request_param.operation
    if operation == "start":
        device.app_start(package_name,activity_name)
    elif operation == "stop":
        device.app_stop(package_name)
    elif operation == "uninstall":
        device.app_uninstall(package_name)
    elif operation == "clear":
        device.app_clear()

    return {
        "message":"success"
    }

@router.get("wlan_ip/{device_id}",description="获取设备wlan ip",summary="获取设备wlan ip")
async def get_wlan_ip(device_id: str="48ef006c"):
    device = adbutils.adb.device(serial=device_id)
    return device.wlan_ip()


@router.post("/press_back", description="按下返回键", summary="按下返回键")
async def press_back(device_id: str):
    device = adbutils.adb.device(serial=device_id)
    device.keyevent(4)  # 发送返回键事件
    return {
        "message": "success"
    }

